package org.jeecg.modules.demo.pay.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.egzosn.pay.common.bean.MethodType;
import com.egzosn.pay.common.bean.PayOrder;
import com.egzosn.pay.common.http.UriVariables;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.util.DateUtils;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.demo.device.entity.ActivationRecord;
import org.jeecg.modules.demo.device.service.IActivationRecordService;
import org.jeecg.modules.demo.pay.entity.PayConfig;
import org.jeecg.modules.demo.pay.entity.PayInfo;
import org.jeecg.modules.demo.pay.enums.PayStatusEnum;
import org.jeecg.modules.demo.pay.enums.PayType;
import org.jeecg.modules.demo.pay.mapper.PayInfoMapper;
import org.jeecg.modules.demo.pay.response.PayResponse;
import org.jeecg.modules.demo.pay.service.IPayConfigService;
import org.jeecg.modules.demo.pay.service.IPayInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

/**
 * @Description: pay_info
 * @Author: xurui-boot
 * @Date:   2022-01-19
 * @Version: V1.0
 */
@Service
public class PayInfoServiceImpl extends ServiceImpl<PayInfoMapper, PayInfo> implements IPayInfoService {

    @Resource
    private IPayConfigService payConfigService;
    @Resource
    private IActivationRecordService activationRecordService;
    @Resource
    private IPayInfoService payInfoService;


    private RedisUtil redisUtil;

    @Override
    public Result<PayInfo> createPayInfo(Map params) {
        Result<PayInfo> result=new Result<PayInfo>();
        //String deviceId=params.get("deviceId").toString();//设备Id
        String  activationId=params.get("activationId").toString();//激活记录及下单的订单id
        String payConfigId=params.get("payConfigId").toString();//支付配置Id
        String outTradeNo= Optional.ofNullable((String)params.get("outTradeNo")).orElse(activationRecordService.orderNo());

        PayConfig payConfig=payConfigService.getById(payConfigId);
        Object obj=redisUtil.get(outTradeNo);
        if(obj==null){
            ActivationRecord activationRecord=activationRecordService.getById(activationId);
            PayInfo payInfo=new PayInfo();
            payInfo.setDeviceId(activationRecord.getDeviceId());
            payInfo.setActivationCost(activationRecord.getActivationCost());
            payInfo.setPayStatus(activationRecord.getPayState());
            payInfo.setPayType(payConfig.getPayType().name());
            payInfo.setTerminalType(activationRecord.getTerminalType());
            payInfo.setOutTradeNo(activationRecord.getOrderNo());
            payInfo.setPayConfigId(payConfigId);
            payInfo.setOrderTitle("激活支付");
            payInfo.setOrderBody("设备激活支付");
           boolean falg= payInfoService.save(payInfo);
           if(falg){
               activationRecord.setPayInfoId(payInfo.getId());
               activationRecord.setPayType(payInfo.getPayType());
               activationRecordService.updateById(activationRecord);
               redisUtil.set(outTradeNo,payInfo,1800);
           }
            result.setResult(payInfo);
        }



        result.setSuccess(true);
        return result;
    }

    @Override
    public Result<Map<String, Object>> getPayInfo(Map params, String tradeType) {
        Result<Map<String,Object>> result = new Result<>();
        Map<String,Object> resMap = new HashMap<String,Object>();
        try {

            Object payId = params.get("payConfigId");//支付方式Id
            Object outTradeNo = params.get("outTradeNo");
            Object handlerName = params.get("handlerName");
            Object openId=params.get("openId");
            //ApiAssert.isNotEmpty("支付handler不能为空", handlerName);
            PayResponse payResponse = payConfigService.getPayResponse(payId.toString(), handlerName.toString());

            Result<PayInfo> resultBody = createPayInfo(params);
            if (resultBody.isSuccess()) {
                PayInfo payInfo = resultBody.getResult();
                String title=payInfo.getOrderTitle();
                String orderBody=payInfo.getOrderBody();
                PayConfig payConfig = payResponse.getPayConfig();

                BigDecimal orderAmount = payInfo.getActivationCost();
                if (oConvertUtils.isNotEmpty(payConfig) && payConfig.getIsTest()) {
                    orderAmount = new BigDecimal("0.01");
                }
               // ApiAssert.isNotEmpty("订单金额不能为空", orderAmount);
                String payType = payResponse.getStorage().getPayType();
                if(BigDecimal.ZERO.compareTo(orderAmount)==0){
                    payType = PayType.balance.name();
                }
                PayOrder payOrder = new PayOrder(title, orderBody, orderAmount, outTradeNo.toString());
                Map<String,Object> extra = new HashMap<String,Object>();
                Object resultInfo = null;
                //APP支付
                if (tradeType.equals("APP") || tradeType.equals("JSAPI")) {
                    extra.put("outTradeNo", outTradeNo);
                    extra.put("payId", payId);
                    payOrder.setTransactionType(PayType.valueOf(payType).getTransactionType(tradeType));
                    if (payType.equals(PayType.aliPay.name())) {
                        resultInfo = UriVariables.getMapToParameters(payResponse.getService().orderInfo(payOrder));
                        resMap.put("aliPayInfo", resultInfo);
                    }
                    if (payType.equals(PayType.wxPay.name())) {
                        //小程序JSAPI支付必须带openid
                        payOrder.setOpenid(openId.toString());
                        Map<String, Object> map = payResponse.getService().orderInfo(payOrder);
                        resMap.putAll(map);

                    }

                }
                //二维码支付
                if (tradeType.equals("NATIVE")) {
                    if (payType.equals(PayType.aliPay.name())) {
                        payOrder.setTransactionType(PayType.valueOf(payType).getTransactionType("SWEEPPAY"));
                    }
                    if (payType.equals(PayType.wxPay.name())) {
                        payOrder.setTransactionType(PayType.valueOf(payType).getTransactionType("NATIVE"));
                    }
                    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                    try {
                        ImageIO.write(payResponse.getService().genQrPay(payOrder), "JPEG", outputStream);
                        resultInfo = outputStream.toByteArray();
                        resMap.put("payInfo", resultInfo);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                //支付宝网页支付
                if (tradeType.equals("PAGE")) {
                    Map<String, Object> orderInfo = payResponse.getService().orderInfo(payOrder);
                    resultInfo = payResponse.getService().buildRequest(orderInfo, MethodType.POST);
                    resMap.put("aliPayInfo", resultInfo);

                }
                resMap.put("payType", payType);
                resMap.put("tradeType", tradeType);
                resMap.put("extra",extra);
                return result;

            } else {
                return result;
            }
        }catch(Exception e){
            //防止出异常，redis里面有payInfo信息而数据库中没有，下次可以支付成功但是通知失败
            redisUtil.del(params.get("outTradeNo").toString());
            throw e;
        }
    }

    @Override
    @Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
    public PayInfo findByOutTradeNo(String outTradeNo) {
        QueryWrapper<PayInfo> cq = new QueryWrapper(PayInfo.class);
        return getOne(cq.eq(true, "outTradeNo", outTradeNo), false);
    }

    @Override
    @Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
    public Boolean validate(String outTradeNo) {
        PayInfo payInfo = findByOutTradeNo(outTradeNo);
        Integer payStatusEnum = payInfo.getPayStatus();
        if (PayStatusEnum.NOPAY.code.equals(payStatusEnum)) {
            return true;
        } else {
            return false;
        }
    }

    @Override
    public Boolean success(Map<String, Object> content) {
        Object outTradeNo = content.get("outTradeNo");
        Boolean tag = false;
        if (oConvertUtils.isNotEmpty(outTradeNo)) {
            ActivationRecord activationRecord =activationRecordService.findByOrderNo(outTradeNo.toString());

            UpdateWrapper updateWrapper = new UpdateWrapper();
            updateWrapper.set(true, "payStatus", PayStatusEnum.PAY.code);
            updateWrapper.set(true, "payDate", DateUtils.getDateTime());

            // updateWrapper.set(true, "orderStatus", orderState);
            updateWrapper.set(true, "fromPay", content.get("fromPay"));
            updateWrapper.set(true, "payType", content.get("payType"));
            updateWrapper.set(true, "transactionType", content.get("transactionType"));
            updateWrapper.eq(true, "outTradeNo", content.get("outTradeNo"));
            tag = update(updateWrapper);
            if (tag) {
                //删除缓存订单
                redisUtil.del(outTradeNo.toString());
            }
        }
        return tag;
    }
}
